package com.yanghui.agent.agentBytebuddy;

import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.*;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;
import redis.clients.jedis.Jedis;

import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;

public class AgentBoot {

    public static class TimeInterceptor {

        @RuntimeType
        public Object intercept(@This Object obj, @Origin Method method, @AllArguments Object[] allArguments,@SuperCall Callable<?> callable) throws Exception{
            long start = System.currentTimeMillis();
            try{
                Jedis jedis = (Jedis)obj;
                System.out.println(jedis.info());
            }catch (Throwable t){
                t.printStackTrace();
            }
            try {
                return callable.call();
            } finally {
                System.out.println("agent:TimeInterceptor:拦截方法：" + method.getDeclaringClass().getName() + "." + method.getName()
                        + ":" + (System.currentTimeMillis() - start) + "ms");
            }
        }
    }

    public static void premain(String agentArgs, Instrumentation inst) throws Exception {
        System.out.println("=================================agent==============================================");
        AgentBuilder agentBuilder = new AgentBuilder.Default();
        AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, module) -> {
            builder = builder
                    .method(ElementMatchers.named("set"))
                    .intercept(MethodDelegation.to(new TimeInterceptor()));
            return builder;
        };
        agentBuilder.type(
                ElementMatchers.named("redis.clients.jedis.Jedis")
            )
            .transform(transformer)
            .with(new Listener())
            .installOn(inst);
    }

    public static class Listener implements AgentBuilder.Listener{

        @Override
        public void onDiscovery(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {
        }

        @Override
        public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, boolean loaded, DynamicType dynamicType) {
        }

        @Override
        public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, boolean loaded) {
        }

        @Override
        public void onError(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded, Throwable throwable) {
            throwable.printStackTrace();
        }

        @Override
        public void onComplete(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {
        }
    }
}
